#define _GNU_SOURCE
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <net/if.h>
#include <signal.h>
#include <sys/select.h>

int wait_conn(int fd, int time_out)
{
	struct timeval tm;
	tm.tv_sec = time_out;
	tm.tv_usec = 0;

	fd_set wset;
	FD_ZERO(&wset);
	FD_SET(fd, &wset);

	int ret = select(fd + 1, NULL, &wset, NULL, &tm);
	if (ret <= 0) {
		return 0;
	}

	int rs = 0;
	socklen_t len = sizeof(rs);
	if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&rs, &len)) {
		return 0;
	}
	return rs == 0;
}

int connect_server(const char *srv, const char *ifname, char *host, int hlen)
{
	struct addrinfo hints, *rp = 0;
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_flags = 0;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = 0;

	if (getaddrinfo(srv, "8192", &hints, &rp)) {
		perror("getaddrinfo");
		exit(0);
	}

	int fd = 0;
	for (struct addrinfo *fp = rp; fp; fp = fp->ai_next) {
		fd = socket(fp->ai_family, fp->ai_socktype | O_NONBLOCK, fp->ai_protocol);
		if (fd < 0) {
			perror("socket");
			continue;
		}

		if (fp->ai_family == AF_INET6) {
			struct sockaddr_in6 *addr = (void *)fp->ai_addr;
			if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
				addr->sin6_scope_id = if_nametoindex(ifname);
			}
		}

		getnameinfo(fp->ai_addr, fp->ai_addrlen, host, hlen, NULL, 0, NI_NUMERICHOST);
		fprintf(stderr, "connect to %s", host);
		if (connect(fd, fp->ai_addr, fp->ai_addrlen) < 0) {
			if (errno != EINPROGRESS || !wait_conn(fd, 2)) {
				fprintf(stderr, " TIME OUT\n");
				close(fd);
				continue;
			}
		}
		fprintf(stderr, " OK\n");
		freeaddrinfo(rp);
		return fd;
	}
	freeaddrinfo(rp);
	return -1;
}

extern int test_icmp(const char *ip, const char *ifname, int time_out);
int main(int argc, char **argv)
{
	if (argc < 2) {
		exit(0);
	}

	if (!test_icmp(argv[1], argv[2], 2)) {
		exit(0);
	}

	char host[INET6_ADDRSTRLEN + IF_NAMESIZE];
	int fd = connect_server(argv[1], argv[2], host, sizeof(host));

	char buf[1024];

	int len = 0;
	while ((len = read(fd, buf, sizeof(buf))) < 0 && errno == EAGAIN)
		;

	close(fd);
	buf[len] = 0;
	printf("%s\nhost=%s\n", buf, host);

	return 0;
}